using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Threading;
using Services;
using System.IO;
using SpaceBattle.Logic.SampleLevel;
using System.IO.IsolatedStorage;
using SpaceBattle.Resources;
using Utilities.Menu.UIElements;

namespace SpaceBattle.Menu
{

    using Game = Microsoft.Xna.Framework.Game;
    using Utilities;

    public enum UpgradeCategory
    {
        Weapons,
        Armors,
        Engines
    }

    public enum BuyOrUpgrade
    { 
        Buy,
        Upgrade,
        None
    }

    public class Shipyard : DrawableGameComponent
    {
        public delegate void SelectShip(ShipType selected_ship);

        Matrix screen_transform;
        SpriteBatch sprite_batch;

        StateEntry c_state;
        GameShipConfig c_ship_config;
        ShipDescription c_ship_desc;
        ArrayList<ShipDescription> ships_stats;

        Button confirm, back, left_arrow, right_arrow, upg_btn, upgrade_button, buy_button;
        Button[] d_btn, t_btn, part_btns;
        Texture2D white_pixel, up_box, confirm_box, arrow, _nameFade_bg, buy_btn_txt, up_btn_txt;
        SpriteFont font32, text_font, font18, font16, small_font, font14, font24;
        SoundEffect click, error;

        List<UpgradeInfo> buy_info, upgrade_info;
        BuyOrUpgrade buy_or_upgrade = BuyOrUpgrade.None;
        int buy_or_upgrade_index = -1;

        private Rectangle _shipNameBGRect = new Rectangle(0, 150, 300, 50);

        int current_ship = 0, weapon_index = 0;
        float press_timer, wait_to_tap = 0.5f;


        public Shipyard(Game game, ShipType selected_ship)
            : base(game)
        {
            c_state = Leaderboard.GetCampaignState();

            current_ship = (int)selected_ship;
        }

        InputManager input_manager;
        public override void Initialize()
        {
            input_manager = new InputManager(Game);
            Game.Components.Add(input_manager);
            input_manager.OnTap += new InputManager.Tap(on_tap);

            ships_stats = (Game.Services.GetService(typeof(ConfigurationService)) as ConfigurationService).Ships;

            c_ship_desc = ships_stats[current_ship];
            c_ship_config = c_state.CampaignState.Ships[current_ship];

            base.Initialize();
        }

        void on_tap(Vector2 tap_position)
        {
            if (wait_to_tap <= 0.0f)
            {
                var p = tap_position.ToPoint(screen_transform);

                if (buy_button.CollisionBox.Contains(p))
                {
                    click.Play(MediaPlayer.Volume, 0.0f, 0.0f);
                    buy_or_upgrade = BuyOrUpgrade.Buy;
                    buy_or_upgrade_index = 0;
                }
                else
                    if (upgrade_button.CollisionBox.Contains(p))
                    {
                        click.Play(MediaPlayer.Volume, 0.0f, 0.0f);
                        buy_or_upgrade = BuyOrUpgrade.Upgrade;
                        buy_or_upgrade_index = 0;
                    }
                    else

                if (confirm.CollisionBox.Contains(p))
                {
                    click.Play(AudioManager.Volume, 0.0f, 0.0f);
                    Leaderboard.SaveCampaignState(c_state);
                    ConfigurationService.ChangeConfiguration(Game, ConfigurationService.GetDefaulConfiguration());
                    StateManager.StartCampaignLevel(Game, (ShipType)current_ship);
                }
                else if (back.CollisionBox.Contains(p) || input_manager.IsBackButtonPressed())
                {
                    click.Play(AudioManager.Volume, 0.0f, 0.0f);
                    Leaderboard.SaveCampaignState(c_state);
                    ConfigurationService.ChangeConfiguration(Game, ConfigurationService.GetDefaulConfiguration());
                    StateManager.SelectCampaignShipSelection(Game);
                }

                else
                {
                    OnTapUpdateButton(p);
                }
            }
        }

        protected override void LoadContent()
        {
            sprite_batch = new SpriteBatch(Game.GraphicsDevice);
            screen_transform = Matrix.CreateScale(GraphicsDevice.Viewport.Width / SpaceBattleGame.DEFAULT_SCR_WIDTH,
                GraphicsDevice.Viewport.Height / SpaceBattleGame.DEFAULT_SCR_HEIGHT, 1.0f);
            confirm_box = Content.Load<Texture2D>("Menu/button_play_ext");
            back_box = Content.Load<Texture2D>("Menu/button_rwd");
            arrow = Content.Load<Texture2D>("Menu/arrow");
            up_box = Content.Load<Texture2D>("Menu/up_box");
            _nameFade_bg = Content.Load<Texture2D>("Menu/name_fade");
            font32 = Content.Load<SpriteFont>("Fonts/OCRAExtended32");
            font18 = Content.Load<SpriteFont>("Fonts/OCRAExtended18");
            font24 = Content.Load<SpriteFont>("Fonts/OCRAExtended24");
            font16 = Content.Load<SpriteFont>("Fonts/OCRAExtended16");
            font14 = Content.Load<SpriteFont>("Fonts/Orator14");
            small_font = Content.Load<SpriteFont>("Fonts/VerySmall");
            text_font = Content.Load<SpriteFont>("Fonts/VerySmall");
            white_pixel = Content.Load<Texture2D>("UI/WhitePixel");
            click = Game.Content.Load<SoundEffect>("Audio/button");
            error = Game.Content.Load<SoundEffect>("Audio/error");
            buy_btn_txt = Content.Load<Texture2D>("Menu/button_cart");
            up_btn_txt = Content.Load<Texture2D>("Menu/button_upgrade");

            confirm = new Button
            {
                Position = new Vector2(GraphicsDevice.Viewport.Width - confirm_box.Width - 10, 
                    GraphicsDevice.Viewport.Height / 2.0f - confirm_box.Height / 2.0f),
                Label = "",
                CollisionBox = new Rectangle(GraphicsDevice.Viewport.Width - confirm_box.Width - 20, 
                    (int)(GraphicsDevice.Viewport.Height / 2.0f - confirm_box.Height / 2.0f) - 10, confirm_box.Width + 20, 
                    confirm_box.Height + 20)
            };

            back = new Button
            {
                Position = new Vector2(10, GraphicsDevice.Viewport.Height / 2.0f - back_box.Height / 2.0f),
                Label = "",
                CollisionBox = new Rectangle(0, (int)(GraphicsDevice.Viewport.Height / 2.0f - back_box.Height / 2.0f) - 10,
                    back_box.Width + 20, back_box.Height + 20)
            };

            buy_button = new Button { CollisionBox = new Rectangle(180,42,(int)(buy_btn_txt.Width * 0.6f), (int)(buy_btn_txt.Height * 0.6f)), 
                Position = new Vector2(106,42), Label = "" };

            upgrade_button = new Button { CollisionBox = new Rectangle(320, 42, buy_button.CollisionBox.Width, buy_button.CollisionBox.Height), 
                Position = new Vector2(296,42), Label = "" };

            var x = (int)(GraphicsDevice.Viewport.Width / 2.0f - up_box.Width / 2.0f) + 90;

            upg_btn = new Button { CollisionBox = new Rectangle(197, 388, up_box.Width, up_box.Height), Label = "", 
                Position = new Vector2(197, 388), Pressed = false};

            left_arrow = new Button()
            {
                CollisionBox = new Rectangle(140, 388, arrow.Width, arrow.Height),
                Label = "",
                Position = new Vector2(140, 388)
            };

            right_arrow = new Button()
            {
                CollisionBox = new Rectangle(upg_btn.CollisionBox.Right + 13, 388, arrow.Width, arrow.Height),
                Label = "",
                Position = new Vector2(upg_btn.CollisionBox.Right + 13, 388)
            };

            #region UpgradeInfo

            upgrade_info = new List<UpgradeInfo>();
            buy_info = new List<UpgradeInfo>();

            var icon_pos = new Vector2(300, 422);
            var title_pos = new Vector2(355, 397);
            var toLevel_pos = new Vector2(497, 428);
            var cost_pos = new Vector2(356,428);

            if (c_state.CampaignState.Ships[current_ship].ArLevel < 3)
            upgrade_info.Add(new UpgradeInfo()
            {
                Icon = new Icon() { Position = icon_pos, Texture = Content.Load<Texture2D>("Menu/Icon/armor_ico") },
                Title = new Label() { Font = font16, Position = title_pos, Text = Strings.SY_UA },
                toLevel = new Label() { Font = small_font, Position = toLevel_pos, Text = Strings.ToLv },
                Cost = new Label() { Font = small_font, Position = cost_pos, Text = Strings.Cost },
                Category = UpgradeCategory.Armors, Index = 0
            });

            if (c_state.CampaignState.Ships[current_ship].ShLevel < 3)
            upgrade_info.Add(new UpgradeInfo()
            {
                Icon = new Icon() { Position = icon_pos, Texture = Content.Load<Texture2D>("Menu/Icon/shield_ico") },
                Title = new Label() { Font = font16, Position = title_pos, Text = Strings.SY_USH },
                toLevel = new Label() { Font = small_font, Position = toLevel_pos, Text = Strings.ToLv },
                Cost = new Label() { Font = small_font, Position = cost_pos, Text = Strings.Cost },
                Category = UpgradeCategory.Armors, Index = 1
            });

            if (c_state.CampaignState.Ships[current_ship].ChLevel < 3)
            upgrade_info.Add(new UpgradeInfo()
            {
                Icon = new Icon() { Position = icon_pos, Texture = Content.Load<Texture2D>("Menu/Icon/battery_ico") },
                Title = new Label() { Font = font16, Position = title_pos, Text = Strings.SY_UC },
                toLevel = new Label() { Font = small_font, Position = toLevel_pos, Text = Strings.ToLv },
                Cost = new Label() { Font = small_font, Position = cost_pos, Text = Strings.Cost },
                Category = UpgradeCategory.Armors, Index = 2
            });

            if (c_state.CampaignState.Ships[current_ship].EnLevel < 3)
            upgrade_info.Add(new UpgradeInfo()
            {
                Icon = new Icon() { Position = icon_pos, Texture = Content.Load<Texture2D>("Menu/Icon/thrust_ico") },
                Title = new Label() { Font = font16, Position = title_pos, Text = Strings.SY_UE },
                toLevel = new Label() { Font = small_font, Position = toLevel_pos, Text = Strings.ToLv },
                Cost = new Label() { Font = small_font, Position = cost_pos, Text = Strings.Cost },
                Category = UpgradeCategory.Engines, Index = 0
            });

            if (c_state.CampaignState.Ships[current_ship].FTLevel < 3)
            upgrade_info.Add(new UpgradeInfo()
            {
                Icon = new Icon() { Position = icon_pos, Texture = Content.Load<Texture2D>("Menu/Icon/warp_ico") },
                Title = new Label() { Font = font16, Position = title_pos, Text = Strings.SY_UWE },
                toLevel = new Label() { Font = small_font, Position = toLevel_pos, Text = Strings.ToLv },
                Cost = new Label() { Font = small_font, Position = cost_pos, Text = Strings.Cost },
                Category = UpgradeCategory.Engines, Index = 1
            });

            for (int i = 0; i < WeaponAsset.Number; i++)
            {
                var w_desc = WeaponConfig.GetWeapon(c_ship_desc.ShipType, (WeaponType)i);
                var available = w_desc.MinLevelRequired <= (int)c_ship_desc.ShipType;

                if (available && c_state.CampaignState.Ships[current_ship].Weapons[i].UpgradeLv < 3)
                {
                    var w = new UpgradeInfo()
                    {
                        Icon = new Icon { Position = icon_pos, Texture = Content.Load<Texture2D>(GetWeaponIconPath(i)) },
                        Title = new Label() { Font = font14, Position = title_pos, Text = GetWeaponTitle(i) },
                        toLevel = new Label() { Font = small_font, Position = toLevel_pos, Text = Strings.ToLv },
                        Cost = new Label() { Font = small_font, Position = cost_pos, Text = Strings.Cost },
                        Available = available, Category = UpgradeCategory.Weapons, Index = i
                    };

                    if (c_ship_config.Weapons[i].UpgradeLv >= 0)
                        upgrade_info.Add(w);
                    else
                        buy_info.Add(w);
                }
            }

            #endregion

            for (int i = 0; i <= (int)WeaponType.Shockwave; i++)
                max_damage += WeaponConfig.GetWeapon(ShipType.PlayerCruiser, (WeaponType)i).Damage * 1.3f;

            base.LoadContent();
        }

        float max_damage = 0.0f;
        protected override void Dispose(bool disposing)
        {
            Game.Services.RemoveService(typeof(IInputManager));

            base.Dispose(disposing);
        }

        public override void Update(GameTime gameTime)
        {
            wait_to_tap -= (float)gameTime.ElapsedGameTime.TotalSeconds;

            press_timer += (float)gameTime.ElapsedGameTime.TotalSeconds;

            if (press_timer > 0.25f)
            {
                left_arrow.Pressed = false;
                right_arrow.Pressed = false;
            }

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            var time = (float)gameTime.TotalGameTime.TotalSeconds;

            var w = GraphicsDevice.Viewport.Width;
            var h = GraphicsDevice.Viewport.Height;

            sprite_batch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, screen_transform);

            sprite_batch.Draw(confirm_box, confirm.Position, Color.White);
            sprite_batch.Draw(back_box, back.Position, Color.White);

            sprite_batch.End();

            DrawShipModel(c_ship_desc, gameTime);

            sprite_batch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, screen_transform);

            sprite_batch.Draw(buy_btn_txt, buy_button.CollisionBox, Color.White);
            sprite_batch.Draw(up_btn_txt, upgrade_button.CollisionBox, Color.White);

            sprite_batch.Draw(_nameFade_bg, _shipNameBGRect, Color.White);

            var c = String.Format(Strings.Credits_l + "{0}", c_state.CampaignState.Credits);
            sprite_batch.DrawString(font18, c, new Vector2(20, 160), Color.White);

            DrawShipStats();

            var a = 1.0f;
            if (buy_or_upgrade_index == -1) a = 0.5f;

            sprite_batch.Draw(up_box, upg_btn.Position, Color.White * a);

            sprite_batch.Draw(arrow, left_arrow.Position, Color.White * a);
            sprite_batch.Draw(arrow, right_arrow.Position, null, Color.White * a, 0, Vector2.Zero, 1.0f, 
                SpriteEffects.FlipHorizontally, 0);

            switch (buy_or_upgrade)
            {
                case BuyOrUpgrade.Buy:
                    DrawPartToBuy();
                    break;
                case BuyOrUpgrade.Upgrade:
                    DrawUpgrade();
                    break;
                default:
                    break;
            }

            sprite_batch.End();

            base.Draw(gameTime);
        }

        #region Draw Helper

        float rot = 0;
        private Texture2D back_box;
        private void DrawShipModel(ShipDescription ship, GameTime gameTime)
        {
            rot += (float)gameTime.ElapsedGameTime.TotalSeconds;

            GraphicsDevice.BlendState = BlendState.Opaque;
            GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;
            GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;

            var view = Matrix.CreateLookAt(Vector3.Up * 100.0f, Vector3.Zero, Vector3.Forward);
            var projection = Matrix.CreatePerspectiveFieldOfView(
              MathHelper.PiOver2, GraphicsDevice.Viewport.AspectRatio, 0.01f, 250.0f);

            var p = new Vector3(-50.0f, 0.0f, -10.0f);

            var model = Content.Load<Model>(ship.ModelPath);
            var scale_matrix = Matrix.CreateScale(40.0f);

            model.EnableShipLighting();
            model.Draw(scale_matrix
                * Matrix.CreateRotationZ(MathHelper.ToRadians(-1))
                //* Matrix.CreateRotationX(rot)
                * Matrix.CreateTranslation(p), view, projection);
        }

        private void DrawShipStats()
        {
            var luv = 0.1f;

            var first_bar_color = new Color(62, 62, 62) * 0.7f;
            var second_bad_color = Color.DarkRed;
            var bar_length = 160;
            var bar_height = 20;
            var y_offset = 50;
            var y_text = 50;
            var y = y_text + 25;
            var x = 450;

            sprite_batch.Draw(white_pixel, new Rectangle(x - 30, y_text - 10, 120, y_offset * 5 + 10), Color.Black * 0.8f);

            var damage = 0.0f;

            for (int i = 0; i < ships_stats[current_ship].PrimaryWeapons.Count; i++)
            {
                var w = c_ship_config.Weapons[(int)ships_stats[current_ship].PrimaryWeapons[i].Type];
                damage += WeaponConfig.GetWeapon((ShipType)current_ship, ships_stats[current_ship].PrimaryWeapons[i].Type).Damage *
                    (1 + (w.UpgradeLv > 0 ? w.UpgradeLv / 10.0f : 0));
            }

            for (int i = 0; i < ships_stats[current_ship].SecondaryWeapons.Count; i++)
            {
                var w = c_ship_config.Weapons[(int)ships_stats[current_ship].SecondaryWeapons[i].Type];
                damage += WeaponConfig.GetWeapon((ShipType)current_ship, ships_stats[current_ship].SecondaryWeapons[i].Type).Damage *
                    (1 + (w.UpgradeLv > 0 ? w.UpgradeLv / 10.0f : 0));
            }

            damage /= max_damage;

            sprite_batch.DrawString(small_font, Strings.Stat_Damage, new Vector2(x - 20, y_text), Color.White);
            sprite_batch.Draw(white_pixel, new Rectangle(x, y, bar_length, bar_height), first_bar_color);
            sprite_batch.Draw(white_pixel, new Rectangle(x, y, (int)(bar_length * Math.Min(1.0f, damage)), bar_height), second_bad_color);

            y += y_offset;
            y_text += y_offset;

            sprite_batch.DrawString(small_font, Strings.Stat_Shield, new Vector2(x - 20, y_text), Color.White);
            sprite_batch.Draw(white_pixel, new Rectangle(x, y, bar_length, bar_height), first_bar_color);
            sprite_batch.Draw(white_pixel, new Rectangle(x, y, (int)(bar_length * Math.Min(1.0f, (c_ship_desc.MaxShield * (1 + c_ship_config.ShLevel / 10.0f)) / (ships_stats[(int)ShipType.PlayerCruiser].MaxShield * 1.3f))), bar_height), second_bad_color);

            y += y_offset;
            y_text += y_offset;

            sprite_batch.DrawString(small_font, Strings.Stat_Armor, new Vector2(x - 20, y_text), Color.White);
            sprite_batch.Draw(white_pixel, new Rectangle(x, y, bar_length, bar_height), first_bar_color);
            sprite_batch.Draw(white_pixel, new Rectangle(x, y, (int)(bar_length * Math.Min(1.0f, c_ship_desc.Armor + c_ship_config.ArLevel * luv)), bar_height), second_bad_color);

            y += y_offset;
            y_text += y_offset;

            sprite_batch.DrawString(small_font, Strings.Stat_Speed, new Vector2(x - 20, y_text), Color.White);
            sprite_batch.Draw(white_pixel, new Rectangle(x, y, bar_length, bar_height), first_bar_color);
            sprite_batch.Draw(white_pixel, new Rectangle(x, y, (int)(bar_length * Math.Min(1.0f, c_ship_desc.Speed + c_ship_config.EnLevel * luv)), bar_height), second_bad_color);

            y += y_offset;
            y_text += y_offset;

            sprite_batch.DrawString(small_font, Strings.Stat_Warp, new Vector2(x - 20, y_text), Color.White);
            sprite_batch.Draw(white_pixel, new Rectangle(x, y, bar_length, bar_height), first_bar_color);
            sprite_batch.Draw(white_pixel, new Rectangle(x, y, (int)(bar_length * Math.Min(1.0f, c_ship_desc.TimeToWarp + c_ship_config.FTLevel * luv)), bar_height), second_bad_color);
        }

        #region Upgrade

        private void DrawUpgrade()
        {
            if (buy_or_upgrade_index < upgrade_info.Count)
            {
                var ui = upgrade_info[buy_or_upgrade_index];
                var lv = GetPartLevel();
                var cost = ui.Category == UpgradeCategory.Weapons ? WeaponUpgradeCost((WeaponType)ui.Index, lv) 
                    : ShipPartUpgradeCost(lv);
                
                sprite_batch.Draw(ui.Icon.Texture, ui.Icon.Position - new Vector2(ui.Icon.Texture.Height / 2.0f, ui.Icon.Texture.Height / 2.0f),
                    Color.White);

                if (lv < 3)
                {
                    sprite_batch.DrawString(ui.toLevel.Font, ui.toLevel.Text + (lv + 1), ui.toLevel.Position, Color.White);
                    sprite_batch.DrawString(ui.Cost.Font, ui.Cost.Text + " " + cost, ui.Cost.Position, cost < c_state.CampaignState.Credits ? Color.White : Color.Red);
                }
                else
                    sprite_batch.DrawString(ui.Cost.Font, Strings.MaxLevel, ui.Cost.Position, Color.Green);
                sprite_batch.DrawString(ui.Title.Font, ui.Title.Text, ui.Title.Position, Color.White);
            }
            else
            {
                sprite_batch.DrawString(font18, Strings.NoPart, new Vector2(GraphicsDevice.Viewport.Width / 2.0f - 
                    font18.MeasureString(Strings.NoPart).X / 2.0f, 410), Color.White);
            }
        }

        private int GetPartLevel()
        {
            int level = 0;
            var ui = buy_or_upgrade == BuyOrUpgrade.Buy ? buy_info[buy_or_upgrade_index] : upgrade_info[buy_or_upgrade_index];
            switch (ui.Category)
            {
                case UpgradeCategory.Weapons:
                    level = c_ship_config.Weapons[ui.Index].UpgradeLv;
                    break;
                case UpgradeCategory.Armors:
                    if (ui.Index == 0) level = c_ship_config.ArLevel;
                    if (ui.Index == 1) level = c_ship_config.ShLevel;
                    if (ui.Index == 2) level = c_ship_config.ChLevel;
                    break;
                case UpgradeCategory.Engines:
                    if (ui.Index == 0) level = c_ship_config.EnLevel;
                    if (ui.Index == 1) level = c_ship_config.FTLevel;
                    break;
                default:
                    break;
            }

            return level;
        }

        private void DrawPartToBuy()
        {
            if (buy_or_upgrade_index < buy_info.Count)
            {
                var ui = buy_info[buy_or_upgrade_index];
                var lv = GetPartLevel();
                var cost = WeaponUpgradeCost((WeaponType)ui.Index, -1);

                sprite_batch.Draw(ui.Icon.Texture, ui.Icon.Position - new Vector2(ui.Icon.Texture.Height / 2.0f, 
                    ui.Icon.Texture.Height / 2.0f), Color.White);
                sprite_batch.DrawString(ui.toLevel.Font, Strings.Buy, ui.toLevel.Position, Color.White);
                sprite_batch.DrawString(ui.Cost.Font, ui.Cost.Text + " " + cost, ui.Cost.Position, cost < c_state.CampaignState.Credits ? Color.White : Color.Red);
                sprite_batch.DrawString(ui.Title.Font, ui.Title.Text, ui.Title.Position, Color.White);
            }
            else
            {
                sprite_batch.DrawString(font18, Strings.NoPart, new Vector2(GraphicsDevice.Viewport.Width / 2.0f -
                    font18.MeasureString(Strings.NoPart).X / 2.0f, 410), Color.White);
            }
        }

        #endregion

        #endregion

        private void Buy()
        {
            switch (buy_info[buy_or_upgrade_index].Category)
            {
                case UpgradeCategory.Weapons:
                    {
                        var i = buy_info[buy_or_upgrade_index].Index;
                        var cost = WeaponUpgradeCost((WeaponType)(i), c_state.CampaignState.Ships[current_ship].Weapons[i].UpgradeLv);

                        if (cost <= c_state.CampaignState.Credits &&
                          c_state.CampaignState.Ships[current_ship].Weapons[i].UpgradeLv < 3)
                        {
                            for (int j = current_ship; j < c_state.Ships.Count; j++)
                            {
                                c_state.Ships[j].Weapons[i].UpgradeLv =
                                    (int)MathHelper.Clamp(c_state.Ships[current_ship].Weapons[i].UpgradeLv + 1, 0, 3);
                                c_state.CampaignState.Ships[j].Weapons[i].UpgradeLv += 1;
                            }
                            c_state.CampaignState.Credits -= cost;
                        }

                        upgrade_info.Add(buy_info[buy_or_upgrade_index]);
                        buy_info.Remove(buy_info[buy_or_upgrade_index]);
                        buy_or_upgrade_index = Math.Max(buy_or_upgrade_index - 1, 0);
                    }
                    break;
                default:
                    break;
            }
        }

        private void Upgrade()
        {
            switch (upgrade_info[buy_or_upgrade_index].Category)
            {
                case UpgradeCategory.Weapons:
                    {
                        var i = upgrade_info[buy_or_upgrade_index].Index;
                        var cost = WeaponUpgradeCost((WeaponType)(i), c_state.CampaignState.Ships[current_ship].Weapons[i].UpgradeLv);

                        if (cost <= c_state.CampaignState.Credits &&
                          c_state.CampaignState.Ships[current_ship].Weapons[i].UpgradeLv < 3)
                        {
                            for (int j = current_ship; j < c_state.Ships.Count; j++)
                            {
                                c_state.Ships[j].Weapons[i].UpgradeLv =
                                    (int)MathHelper.Clamp(c_state.Ships[current_ship].Weapons[i].UpgradeLv + 1, 0, 3);
                                c_state.CampaignState.Ships[j].Weapons[i].UpgradeLv += 1;
                            }
                            c_state.CampaignState.Credits -= cost;
                        }
                    }
                    break;
                case UpgradeCategory.Armors:
                    {
                        switch (upgrade_info[buy_or_upgrade_index].Index)
                        {
                            case 0:
                                { 
                                    var cost = ShipPartUpgradeCost(c_state.CampaignState.Ships[current_ship].ArLevel);

                                    if (cost <= c_state.CampaignState.Credits && c_state.CampaignState.Ships[current_ship].ArLevel < 3)
                                    {
                                        c_state.Ships[current_ship].ArLevel = (int)MathHelper.Clamp(c_state.Ships[current_ship].ArLevel + 1, 0, 3);
                                        c_state.CampaignState.Ships[current_ship].ArLevel += 1;
                                        c_state.CampaignState.Credits -= cost;
                                    }
                                } break;
                            case 1:
                                {
                                    var cost = ShipPartUpgradeCost(c_state.CampaignState.Ships[current_ship].ShLevel);

                                    if (cost <= c_state.CampaignState.Credits && c_state.CampaignState.Ships[current_ship].ShLevel < 3)
                                    {
                                        c_state.Ships[current_ship].ShLevel = (int)MathHelper.Clamp(c_state.Ships[current_ship].ShLevel + 1, 0, 3);
                                        c_state.CampaignState.Ships[current_ship].ShLevel += 1;
                                        c_state.CampaignState.Credits -= cost;
                                    }
                                } break;
                            case 2:
                                {
                                    var cost = ShipPartUpgradeCost(c_state.CampaignState.Ships[current_ship].ChLevel);

                                    if (cost <= c_state.CampaignState.Credits && c_state.CampaignState.Ships[current_ship].ChLevel < 3)
                                    {
                                        c_state.Ships[current_ship].ChLevel = (int)MathHelper.Clamp(c_state.Ships[current_ship].ChLevel + 1, 0, 3);
                                        c_state.CampaignState.Ships[current_ship].ChLevel += 1;
                                        c_state.CampaignState.Credits -= cost;
                                    }
                                } break;
                            default: break;
                        }
                    }
                    break;
                case UpgradeCategory.Engines:
                    {
                        switch (upgrade_info[buy_or_upgrade_index].Index)
                        {
                            case 0:
                                {
                                    var cost = ShipPartUpgradeCost(c_state.CampaignState.Ships[current_ship].EnLevel);

                                    if (cost <= c_state.CampaignState.Credits && c_state.CampaignState.Ships[current_ship].EnLevel < 3)
                                    {
                                        c_state.Ships[current_ship].EnLevel = (int)MathHelper.Clamp(c_state.Ships[current_ship].EnLevel + 1, 0, 3);
                                        c_state.CampaignState.Ships[current_ship].EnLevel += 1;
                                        c_state.CampaignState.Credits -= cost;
                                    }
                                } break;
                            case 1:
                                {
                                    var cost = ShipPartUpgradeCost(c_state.CampaignState.Ships[current_ship].FTLevel);

                                    if (cost <= c_state.CampaignState.Credits && c_state.CampaignState.Ships[current_ship].FTLevel < 3)
                                    {
                                        c_state.Ships[current_ship].FTLevel = (int)MathHelper.Clamp(c_state.Ships[current_ship].FTLevel + 1, 0, 3);
                                        c_state.CampaignState.Ships[current_ship].FTLevel += 1;
                                        c_state.CampaignState.Credits -= cost;
                                    }
                                } break;
                            default: break;
                        }
                    }
                    break;
                default: break;
            }
        }

        private void OnTapUpdateButton(Point p)
        {
            if (!left_arrow.Pressed && left_arrow.CollisionBox.Contains(p))
            {
                if (buy_or_upgrade != BuyOrUpgrade.None)
                {
                    var mod = buy_or_upgrade == BuyOrUpgrade.Upgrade ? upgrade_info.Count : buy_info.Count;
                    if (mod != 0)
                    {
                        click.Play(AudioManager.Volume, 0, 0);
                        buy_or_upgrade_index = ((buy_or_upgrade_index - 1) % mod + mod) % mod;
                        left_arrow.Pressed = true;
                        press_timer = 0.0f;
                    }
                    else
                        error.Play(AudioManager.Volume, 0, 0);
                }
                else
                    error.Play(AudioManager.Volume, 0, 0);
            }
            else if (!right_arrow.Pressed && right_arrow.CollisionBox.Contains(p))
            {
                if (buy_or_upgrade != BuyOrUpgrade.None)
                {
                    var mod = buy_or_upgrade == BuyOrUpgrade.Upgrade ? upgrade_info.Count : buy_info.Count;
                    if (mod != 0)
                    {
                        buy_or_upgrade_index = (buy_or_upgrade_index + 1) % mod;
                        right_arrow.Pressed = true;
                        press_timer = 0.0f;
                        click.Play(AudioManager.Volume, 0, 0);
                    }
                    else
                        error.Play(AudioManager.Volume, 0, 0);
                }
                else
                    error.Play(AudioManager.Volume, 0, 0);
            }
            else if (upg_btn.CollisionBox.Contains(p))
            {
                switch (buy_or_upgrade)
                {
                    case BuyOrUpgrade.Buy:
                        {
                            if (buy_or_upgrade_index < buy_info.Count && buy_or_upgrade_index > -1)
                            {
                                Buy(); 
                            }
                            break;
                        }
                    case BuyOrUpgrade.Upgrade:
                        {
                            if (buy_or_upgrade_index < upgrade_info.Count && buy_or_upgrade_index > -1)
                            {
                                Upgrade();
                            }
                            break;
                        }
                    default:
                        break;
                }
            }
        }

        #region Support Method

        private int ShipPartUpgradeCost(int current_level)
        {
            return (current_ship + 1) * 10 + 10 * (current_level + 1);
        }

        private int WeaponUpgradeCost(WeaponType type, int current_level)
        {
            int cost = 75;
            int wi = (int)type;

            if ((int)type >= (int)WeaponType.Nuke)
            {
                cost = 100;
                wi = 1 + (int)type - (int)WeaponType.Nuke;
            }

            if (current_level == -1)
            {
                cost += (current_ship + 1 + wi) * 5;
            }
            else
                cost += ShipPartUpgradeCost(current_level);

            if (type == WeaponType.Shockwave && current_level == -1)
                cost = 3500;

            return cost;
        }

        private string GetWeaponTitle(int index)
        {
            return ((WeaponType)index).ToString().Replace('_', ' ');
        }

        private string GetWeaponIconPath(int index)
        {
            return "Menu/Icon/" + ((WeaponType)index).ToString();
        }

        #endregion

        #region Proprieties

        ContentManager Content { get { return Game.Content; } }

        #endregion
    }

    #region Support Struct

    public struct UpgradeInfo
    {
        public Label Title;
        public Label toLevel;
        public Label Cost;
        public Icon Icon;
        public bool Available;
        public int Index;
        public UpgradeCategory Category;
    }

    public struct Icon
    {
        public Texture2D Texture;
        public Vector2 Position;
    }

    public struct Label
    {
        public string Text;
        public Vector2 Position;
        public SpriteFont Font;
    }

    #endregion
}
